﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.IO;
using System.Windows.Resources;
using System.Linq;

namespace BattleforgeAssault
{
    /// <summary>
    /// A game card
    /// </summary>
    public class Card : GameObject
    {
        #region Properties

        #region Modified Stats

        private int _cost = 0;
        public int Cost { get { return Game.GetModified(this, "Cost", _cost); } set { _cost = value; RaisePropertyChanged("Cost"); } }

        private int _tokens = 0;
        public int Tokens { get { return Game.GetModified(this, "Tokens", _tokens); } set { _tokens = value; RaisePropertyChanged("Tokens"); } }

        private int _loyalty = 0;
        public int Loyalty { get { return Game.GetModified(this, "Loyalty", _loyalty); } set { _loyalty = value; RaisePropertyChanged("Loyalty"); } }

        #endregion Modified Stats

        private List<Types.Traits> _traits = new List<Types.Traits>();
        public List<Types.Traits> Traits { get { return _traits; } set { _traits = value; RaisePropertyChanged("Traits"); } }

        private List<Types.Keywords> _keywords = new List<Types.Keywords>();
        public List<Types.Keywords> Keywords { get { return _keywords; } set { _keywords = value; RaisePropertyChanged("Keywords"); } }

        private List<Effect> _effects = new List<Effect>();
        public List<Effect> Effects { get { return _effects; } set { _effects = value; RaisePropertyChanged("Effects"); } }

        private Player _controller = null;
        public Player Controller { get { return _controller; } set { _controller = value; RaisePropertyChanged("Controller"); } }

        public Game Game { get { return _owner.Game; } }

        private CardView _view = null;
        public CardView View { get { return _view; } set { _view = value; } }

        private Location _location = null;
        public Location Location { get { return _location; } set { _location = value; RaisePropertyChanged("Location"); } }

        private string _title = "Title";
        public string Title { get { return _title; } set { _title = value; RaisePropertyChanged("Title"); } }

        private Action _action = new Action();
        public Action Action { get { return _action; } set { _action = value; RaisePropertyChanged("Action"); } }

        private BitmapImage _front = null;
        public BitmapImage Front
        {
            get
            {
                if (_front == null)
                {
                    string localName = string.Format("{0}-{1}.jpg", (int)Set, Number);
                    string remoteName = string.Format("http://deckbox.org/system/images/whi/cards/{0}-{1}.jpg", Types.GetWebSetNumber(Set, Number), Number);
                    _front = Util.FindResource(localName, remoteName, "front.png");
                }
                return _front;
            }
            set { _front = value; RaisePropertyChanged("Front"); }
        }

        private BitmapImage _back = null;
        public BitmapImage Back
        {
            get
            {
                if (_back == null)
                {
                    _back = Util.FindResource("whi_card_back.jpg", "http://deckbox.org/images/whi_card_back.jpg", "back.png");
                }
                return _back;
            }
            set { _back = value; RaisePropertyChanged("Back"); }
        }

        private Types.Sets _set = Types.Sets.Core;
        public Types.Sets Set { get { return _set; } set { _set = value; RaisePropertyChanged("Set"); } }

        private int _number = 0;
        public int Number { get { return _number; } set { _number = value; RaisePropertyChanged("Number"); } }

        public IEnumerable<Card> Attachments { get { return Game.Cards.Where(card => card is Support && ((Support)card).AttachedTo == this); } }

        private int _turnEnteredPlay = -1;
        public int TurnEnteredPlay { get { return _turnEnteredPlay; } set { _turnEnteredPlay = value; RaisePropertyChanged("TurnEnteredPlay"); } }

        private int _turnLeftPlay = -1;
        public int TurnLeftPlay { get { return _turnLeftPlay; } set { _turnLeftPlay = value; RaisePropertyChanged("TurnLeftPlay"); } }

        private Player _owner = null;
        public Player Owner { get { return _owner; } set { _owner = value; RaisePropertyChanged("Owner"); } }

        private Types.Races _race = Types.Races.Neutral;
        public Types.Races Race { get { return _race; } set { _race = value; RaisePropertyChanged("Race"); } }

        private bool _isCorrupt = false;
        public bool IsCorrupt
        {
            get { return _isCorrupt; }
            set
            {
                if (value == true && _isCorrupt == false)
                {
                    _isCorrupt = true;
                    View.Rotate(0, 90, 0.5);
                }
                else if (value == false && _isCorrupt == true)
                {
                    _isCorrupt = false;
                    View.Rotate(90, 0, 0.5);
                }
                RaisePropertyChanged("IsCorrupt");
            }
        }

        private bool _isDeveloped = false;
        public bool IsDeveloped
        {
            get { return _isDeveloped; }
            set
            {
                if (value == true && _isDeveloped == false)
                {
                    _isDeveloped = true;
                    View.Flip(.5);
                }
                else if (value == false && _isDeveloped == true)
                {
                    _isDeveloped = false;
                    View.Flip(.5);
                }
                RaisePropertyChanged("IsDeveloped");
            }
        }

        private bool _isUnique = false;
        public bool IsUnique { get { return _isUnique; } set { _isUnique = value; RaisePropertyChanged("IsUnique"); } }

        private string _text = "";
        public string Text { get { return _text; } set { _text = value; RaisePropertyChanged("Text"); } }

        private string _flavorText = "";
        public string FlavorText { get { return _flavorText; } set { _flavorText = value; RaisePropertyChanged("FlavorText"); } }

        #endregion

        #region Event Methods

        /// <summary>
        /// Called when the card is removed from play.
        /// </summary>
        /// <remarks>
        /// Leaves play is when a card that is in an in play zone goes into an out of play zone, 
        /// such as back into a hand, deck, or discard pile. 
        /// </remarks>
        public virtual void LeavePlay()
        {
            Game.CheckEffects(this, "PreLeavePlay");
            TurnLeftPlay = Game.Turn;
            Messager.SendMessage("{0} leaving play", this);
            foreach (var effect in Effects)
            {
                Game.RemoveEffect(effect);
            }
            Location = Owner.Discard;
            Game.CheckEffects(this, "PostLeavePlay");
        }

        /// <summary>
        /// Called when the card is put in play.
        /// </summary>
        /// <remarks>
        /// Any card that is played or put into play is also considered to have entered play. 
        /// Cards may enter play from the hand, deck, or the discard pile. 
        /// </remarks>
        public virtual void EnterPlay()
        {
            TurnEnteredPlay = Game.Turn;
            Messager.SendMessage("{0} entering play", this);
            foreach (var effect in Effects)
            {
                Game.AddEffect(effect);
            }
        }

        /// <summary>
        /// Called when the card is sacrificed.
        /// </summary>
        /// <remarks>
        /// Sacrifice means to put a card that you control into its owner’s discard pile. 
        /// It cannot be cancelled or prevented by other effects. 
        /// </remarks>
        public virtual void Sacrifice()
        {
            TurnLeftPlay = Game.Turn;
            Messager.SendMessage("{0} being sacrificed", this);
            LeavePlay();
        }

        /// <summary>
        /// Called when the card is destroyed.
        /// </summary>
        /// <remarks>
        /// Destroy means to put a card that is in play into it’s owner’s discard pile. 
        /// It is important to note that sacrificing a unit is not destroying it and vice versa. 
        /// </remarks>
        public virtual void Destroy()
        {
            TurnLeftPlay = Game.Turn;
            Messager.SendMessage("{0} being destroyed", this);
            LeavePlay();
        }

        /// <summary>
        /// Corrupt or Uncorrupt the card
        /// </summary>
        /// <param name="value">True to corrupt, false to uncorrupt</param>
        public void Corrupt(bool value)
        {
            if (value == true && IsCorrupt == false)
            {
                IsCorrupt = true;
                View.Rotate(0, 90, 0.5);
            }
            else if (value == false && IsCorrupt == true)
            {
                IsCorrupt = false;
                View.Rotate(90, 0, 0.5);
            }
        }

        #endregion Event Methods

        #region Helper Methods

        public override string ToString()
        {
            return Title;
        }

        #endregion Helper Methods
    } // Card
} // Namespace
